package org.loofer.ext.utils;

import android.os.Handler;
import android.os.Handler.Callback;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;

public class TimingManager {
    private static final int STATE_PAUSED = 2;
    private static final int STATE_RESUMED = 1;
    private static final int STATE_STOPPED = 3;
    private static final int WHAT_CANCEL_TASK = 2;
    private static final int WHAT_CLEAR_TASK = 3;
    private static final int WHAT_EXECUTE_INDIE_TASK = 6;
    private static final int WHAT_PAUSE = 7;
    private static final int WHAT_RESUME = 8;
    private static final int WHAT_SCHEDULE_INDIE_TASK = 5;
    private static final int WHAT_SCHEDULE_TASK = 1;
    private static final int WHAT_STOP = 9;
    private static final int WHAT_TICK = 4;
    private static final AtomicInteger sId = new AtomicInteger();
    private final HashMap<Integer, TaskRecord> mIndieTaskMap;
    private long mLastPauseTime;
    private final Looper mOwnLooper;
    private volatile int mState;
    private final ArrayList<TaskRecord> mTaskList;
    private final HashMap<Integer, TaskRecord> mTaskMap;
    private long mTickPeriod;
    private final Handler mTimingHandler;

    static final class TaskRecord {
        final long delay;
        final int id;
        long initialTime;
        long lastExecuteTime = 0;
        final long period;
        final Runnable runnable;

        public TaskRecord(int _id, Runnable _runnable, long _delay, long _interval) {
            this.id = _id;
            this.runnable = _runnable;
            this.delay = _delay;
            this.period = _interval;
        }
    }

    static final class TimingThread extends HandlerThread {
        public TimingThread(String name, int priority) {
            super(name, priority);
        }
    }

    public TimingManager(String name) {
        this(name, 10);
    }

    public TimingManager(String name, int threadPriority) {
        this(createTimingThread(name, threadPriority).getLooper(), true);
    }

    public TimingManager(Looper looper) {
        this(looper, false);
    }

    private TimingManager(Looper looper, boolean ownLooper) {
        this.mTaskList = new ArrayList();
        this.mTaskMap = new HashMap();
        this.mIndieTaskMap = new HashMap();
        this.mState = 1;
        this.mTimingHandler = new Handler(looper, new Callback() {
            public boolean handleMessage(Message msg) {
                TimingManager.this.handleMessageImpl(msg);
                return true;
            }
        });
        if (!ownLooper) {
            looper = null;
        }
        this.mOwnLooper = looper;
    }

    private static long now() {
        return SystemClock.uptimeMillis();
    }

    private static long computeCommonDivisor(long v1, long v2) {
        long m = 1;
        if (v1 < v2) {
            m = v1;
            v1 = v2;
            v2 = m;
        }
        while (m != 0) {
            m = v1 % v2;
            v1 = v2;
            v2 = m;
        }
        return v1;
    }

    private static TaskRecord createTaskRecord(Runnable runnable, long delay, long interval) {
        return new TaskRecord(sId.getAndIncrement(), runnable, delay, interval);
    }

    private static HandlerThread createTimingThread(String name, int threadPriority) {
        HandlerThread thread = new TimingThread(name, threadPriority);
        thread.start();
        return thread;
    }

    public int schedule(Runnable runnable, long period) {
        return schedule(runnable, 0, period);
    }

    public int schedule(Runnable runnable, long delay, long period) {
        checkNotStopped("Timing is stopped");
        if (period <= 0) {
            throw new IllegalArgumentException("period should be greater than 0");
        }
        if (delay < 0) {
            delay = 0;
        }
        TaskRecord record = createTaskRecord(runnable, delay, period);
        Message msg = Message.obtain();
        msg.what = 1;
        msg.obj = record;
        this.mTimingHandler.sendMessage(msg);
        return record.id;
    }

    public int scheduleIndie(Runnable runnable, long period) {
        return scheduleIndie(runnable, 0, period);
    }

    public int scheduleIndie(Runnable runnable, long delay, long period) {
        checkNotStopped("Timing is stopped");
        if (period <= 0) {
            throw new IllegalArgumentException("period should be greater than 0");
        }
        if (delay < 0) {
            delay = 0;
        }
        TaskRecord record = createTaskRecord(runnable, delay, period);
        Message msg = Message.obtain();
        msg.what = 5;
        msg.obj = record;
        this.mTimingHandler.sendMessage(msg);
        return record.id;
    }

    public void cancel(Runnable runnable) {
        checkNotStopped("Timing is stopped");
        Message msg = Message.obtain();
        msg.what = 2;
        msg.obj = runnable;
        this.mTimingHandler.sendMessage(msg);
    }

    public void cancel(int id) {
        checkNotStopped("Timing is stopped");
        Message msg = Message.obtain();
        msg.what = 2;
        msg.arg1 = id;
        this.mTimingHandler.sendMessage(msg);
    }

    public void clear() {
        checkNotStopped("Timing is stopped");
        Message msg = Message.obtain();
        msg.what = 3;
        this.mTimingHandler.sendMessage(msg);
    }

    public void pause() {
        checkNotStopped("Cannot pause already stopped timing");
        Message msg = Message.obtain();
        msg.what = 7;
        this.mTimingHandler.sendMessageAtFrontOfQueue(msg);
    }

    public void resume() {
        checkNotStopped("Cannot resume already stopped timing");
        Message msg = Message.obtain();
        msg.what = 8;
        this.mTimingHandler.sendMessageAtFrontOfQueue(msg);
    }

    public void stop() {
        checkNotStopped("Timing is already stopped");
        Message msg = Message.obtain();
        msg.what = 9;
        this.mTimingHandler.sendMessageAtFrontOfQueue(msg);
    }

    public final boolean isResumed() {
        return this.mState == 1;
    }

    public final boolean isStopped() {
        return this.mState == 3;
    }

    private void handleMessageImpl(Message msg) {
        switch (msg.what) {
            case 1:
                performScheduleTask((TaskRecord) msg.obj);
                return;
            case 2:
                if (msg.obj != null) {
                    performCancelTask((Runnable) msg.obj);
                    return;
                } else {
                    performCancelTask(msg.arg1);
                    return;
                }
            case 3:
                performClearTask();
                return;
            case 4:
                if (isResumed()) {
                    performTick();
                    return;
                } else {
                    continueTick();
                    return;
                }
            case 5:
                performScheduleIndieTask((TaskRecord) msg.obj);
                return;
            case 6:
                if (isResumed()) {
                    performIndie(msg.arg1);
                    return;
                } else {
                    continueIndie(msg.arg1);
                    return;
                }
            case 7:
                if (updateState(2)) {
                    performPause();
                    return;
                }
                return;
            case 8:
                if (updateState(1)) {
                    performResume();
                    return;
                }
                return;
            case 9:
                if (updateState(3)) {
                    performStop();
                    return;
                }
                return;
            default:
                return;
        }
    }

    private void performScheduleTask(TaskRecord record) {
        record.initialTime = now();
        this.mTaskList.add(record);
        this.mTaskMap.put(Integer.valueOf(record.id), record);
        if (updateTickPeriod(record.period)) {
            restartTick();
        } else {
            startTick();
        }
    }

    private void performScheduleIndieTask(TaskRecord record) {
        record.initialTime = now();
        this.mIndieTaskMap.put(Integer.valueOf(record.id), record);
        startIndie(record.id);
    }

    private void performCancelTask(Runnable runnable) {
        Iterator<TaskRecord> iterator = this.mTaskList.iterator();
        while (iterator.hasNext()) {
            TaskRecord record = (TaskRecord) iterator.next();
            if (record.runnable.equals(runnable)) {
                iterator.remove();
                this.mTaskMap.remove(Integer.valueOf(record.id));
            }
        }
        if (this.mTaskList.isEmpty()) {
            stopTick();
        }
        Iterator<Entry<Integer, TaskRecord>> indieIterator = this.mIndieTaskMap.entrySet().iterator();
        while (indieIterator.hasNext()) {
            if (((TaskRecord) ((Entry) indieIterator.next()).getValue()).runnable.equals(runnable)) {
                indieIterator.remove();
            }
        }
        if (this.mIndieTaskMap.isEmpty()) {
            stopIndie();
        }
    }

    private void performCancelTask(int id) {
        TaskRecord record = (TaskRecord) this.mTaskMap.get(Integer.valueOf(id));
        if (record != null && this.mTaskList.remove(record) && this.mTaskList.isEmpty()) {
            stopTick();
        }
        if (this.mIndieTaskMap.remove(Integer.valueOf(id)) != null && this.mIndieTaskMap.isEmpty()) {
            stopIndie();
        }
    }

    private void performClearTask() {
        this.mTaskList.clear();
        this.mTaskMap.clear();
        stopTick();
        this.mIndieTaskMap.clear();
        stopIndie();
    }

    private void startTick() {
        if (!this.mTimingHandler.hasMessages(4)) {
            this.mTimingHandler.sendEmptyMessage(4);
        }
    }

    private void restartTick() {
        this.mTimingHandler.removeMessages(4);
        this.mTimingHandler.sendEmptyMessage(4);
    }

    private void stopTick() {
        this.mTimingHandler.removeMessages(4);
    }

    private void continueTick() {
        this.mTimingHandler.sendEmptyMessageDelayed(4, getTickPeriod());
    }

    private void performTick() {
        if (this.mTaskList.isEmpty()) {
            stopTick();
            return;
        }
        continueTick();
        long now = now();
        Iterator it = this.mTaskList.iterator();
        while (it.hasNext()) {
            TaskRecord record = (TaskRecord) it.next();
            if ((record.lastExecuteTime == 0 && record.initialTime + record.delay <= now) || record.lastExecuteTime + record.period <= now) {
                record.runnable.run();
                record.lastExecuteTime = now;
            }
        }
    }

    private long getTickPeriod() {
        return this.mTickPeriod;
    }

    private boolean updateTickPeriod(long newPeriod) {
        if (newPeriod <= 0) {
            return false;
        }
        long prev = this.mTickPeriod;
        if (this.mTickPeriod <= 0) {
            this.mTickPeriod = newPeriod;
        } else {
            this.mTickPeriod = computeCommonDivisor(this.mTickPeriod, newPeriod);
        }
        if (this.mTickPeriod != prev) {
            return true;
        }
        return false;
    }

    private void startIndie(int id) {
        TaskRecord record = (TaskRecord) this.mIndieTaskMap.get(Integer.valueOf(id));
        if (record != null) {
            Message msg = Message.obtain();
            msg.what = 6;
            msg.arg1 = record.id;
            this.mTimingHandler.sendMessageDelayed(msg, record.delay);
        }
    }

    private void restartIndie(int id) {
        Message msg = Message.obtain();
        msg.what = 6;
        msg.arg1 = id;
        this.mTimingHandler.sendMessage(msg);
    }

    private void stopIndie() {
        this.mTimingHandler.removeMessages(6);
    }

    private void continueIndie(int id) {
        TaskRecord record = (TaskRecord) this.mIndieTaskMap.get(Integer.valueOf(id));
        if (record != null) {
            Message msg = Message.obtain();
            msg.what = 6;
            msg.arg1 = record.id;
            this.mTimingHandler.sendMessageDelayed(msg, record.period);
        }
    }

    private void performIndie(int id) {
        if (this.mIndieTaskMap.isEmpty()) {
            stopIndie();
            return;
        }
        TaskRecord record = (TaskRecord) this.mIndieTaskMap.get(Integer.valueOf(id));
        if (record != null) {
            continueIndie(id);
            record.runnable.run();
            record.lastExecuteTime = now();
        }
    }

    private void checkNotStopped(String msg) {
        if (this.mState == 3) {
            throw new IllegalStateException(msg);
        }
    }

    private boolean updateState(int state) {
        boolean allow = false;
        switch (state) {
            case 1:
                if (this.mState != 3) {
                    if (this.mState == 2) {
                        allow = true;
                    } else {
                        allow = false;
                    }
                    break;
                }
                throw new RuntimeException("Cannot resume already stopped timing");
            case 2:
                if (this.mState != 3) {
                    if (this.mState == 1) {
                        allow = true;
                    } else {
                        allow = false;
                    }
                    break;
                }
                throw new RuntimeException("Cannot pause already stopped timing");
            case 3:
                if (this.mState != 3) {
                    allow = this.mState != 3;
                    break;
                }
                throw new RuntimeException("Timing is already stopped");
        }
        if (allow) {
            this.mState = state;
        }
        return allow;
    }

    private void performPause() {
        this.mLastPauseTime = now();
    }

    private void performResume() {
        long now = now();
        if (this.mLastPauseTime > 0 && this.mLastPauseTime + this.mTickPeriod <= now) {
            restartTick();
        }
        for (TaskRecord record : this.mIndieTaskMap.values()) {
            if (this.mLastPauseTime > 0 && this.mLastPauseTime + record.period <= now) {
                restartIndie(record.id);
            }
        }
        this.mLastPauseTime = 0;
    }

    private void performStop() {
        if (this.mOwnLooper != null) {
            this.mOwnLooper.quit();
        }
        this.mTaskList.clear();
        this.mTaskMap.clear();
        this.mIndieTaskMap.clear();
    }
}
